package cn.juque.jdfsystem.threads;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.Digester;
import cn.juque.common.constants.NumberConstant;
import cn.juque.common.constants.StringConstants;
import cn.juque.common.utils.HttpClientUtil;
import cn.juque.common.utils.dto.GetDTO;
import cn.juque.jdfsystem.cache.ConfigInfoCache;
import cn.juque.jdfsystem.cache.PlatformInfoCache;
import cn.juque.jdfsystem.cache.RegisterInfoCache;
import cn.juque.jdfsystem.contants.UrlConstants;
import cn.juque.jdfsystem.entity.FileInfo;
import cn.juque.jdfsystem.entity.PlatformInfo;
import cn.juque.jdfsystem.enums.ConfigCodeEnum;
import cn.juque.jdfsystem.service.IFileInfoService;
import cn.juque.lucenecandy.cache.IpCache;
import cn.juque.lucenecandy.core.constants.StrConstant;
import cn.juque.lucenecandy.core.utils.SignatureUtil;
import cn.juque.lucenecandy.helper.IndexHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * @author juque
 * @version 1.0.0
 * <ul>
 *     <li>DownloadFileThreadPool</li>
 * </ul>
 * @date 2023-12-13 16:54:22
 **/
@Slf4j
@Component("downloadFileThreadPool")
public class DownloadFileThreadPool {

    private static final ThreadFactory THREAD_FACTORY = ThreadUtil.newNamedThreadFactory("dwlod-", true);

    private static final ExecutorService EXECUTOR = new ThreadPoolExecutor(2, 200,
            0,
            TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(2000), THREAD_FACTORY);


    @Resource
    private RegisterInfoCache registerInfoCache;

    @Resource
    private ConfigInfoCache configInfoCache;

    @Resource
    private PlatformInfoCache platformInfoCache;

    @Resource
    private IpCache ipCache;

    @Resource
    private IFileInfoService fileInfoService;

    @Resource
    private IndexHelper indexHelper;

    public void execute(List<String> ipList, FileInfo fileInfo) {
        EXECUTOR.execute(() -> this.downloadFile(ipList, fileInfo));
    }

    public Boolean submit(List<String> ipList, FileInfo fileInfo) {
        try {
            Future<Boolean> future = EXECUTOR.submit(() -> this.downloadFile(ipList, fileInfo));
            return future.get();
        } catch (InterruptedException e) {
            log.error("文件ID:{}, 下载失败", fileInfo.getId(), e);
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            log.error("文件ID:{}, 下载失败", fileInfo.getId(), e);
        }
        return false;
    }

    /**
     * 文件下载
     *
     * @param ipList   ip列表
     * @param fileInfo 文件信息
     * @return boolean
     */
    private Boolean downloadFile(List<String> ipList, FileInfo fileInfo) {
        // 只有同工作空间才下载文件
        String workspaceId = this.configInfoCache.getValue(ConfigCodeEnum.WORKSPACE_ID.getCode());
        if (!fileInfo.getWorkspaceId().equals(workspaceId)) {
            return true;
        }
        Set<String> targetIpSet = CollUtil.newHashSet();
        if (CollUtil.isNotEmpty(ipList)) {
            targetIpSet.addAll(ipList);
        }
        Set<String> ips = this.registerInfoCache.getValidIpMap(workspaceId, false).get(workspaceId);
        targetIpSet = targetIpSet.stream().filter(ips::contains).collect(Collectors.toSet());
        if (CollUtil.isEmpty(targetIpSet)) {
            targetIpSet.clear();
            targetIpSet.addAll(ips);
        }
        // 变更目录
        File parentFile = FileUtil.file(fileInfo.getServerPath());
        String parentPath = this.fileInfoService.createServerPath(parentFile.getName());
        fileInfo.setServerPath(parentPath);
        String serverFileName = fileInfo.getId() + StringConstants.POINT + fileInfo.getFileExt();
        File file = FileUtil.file(parentPath, serverFileName);
        Date offsetDate = DateUtil.offsetSecond(new Date(), NumberConstant.ONE_HUNDRED);
        long timestamp = offsetDate.getTime();
        Digester digester = SecureUtil.sha1();
        digester.setSalt(String.valueOf(timestamp).getBytes(StandardCharsets.UTF_8));
        PlatformInfo platformInfo = this.platformInfoCache.get(fileInfo.getPlatformId(), false);
        boolean flag = false;
        for (String ip : targetIpSet) {
            String sign = digester.digestHex(platformInfo.getSecret() + platformInfo.getId());
            String urlPath = CharSequenceUtil.format(UrlConstants.MESSAGE_FILE_VIEW, fileInfo.getId(), fileInfo.getPlatformId(), sign, timestamp);
            String url = this.ipCache.buildUrl(ip, urlPath);
            url = SignatureUtil.buildUrl(url);
            GetDTO getDTO = new GetDTO(url, null, null, null);
            flag = HttpClientUtil.download(getDTO, file.getAbsolutePath());
            if (Boolean.TRUE.equals(flag)) {
                break;
            }
        }
        if (flag) {
            fileInfo.setAttachInfo(CollUtil.newHashSet(StrConstant.NOT_SYNC));
            this.indexHelper.updateDocumentById(fileInfo);
        } else {
            log.error("文件ID:{},文件名称:{}, 在工作空间:{} 下载失败",
                    fileInfo.getId(), fileInfo.getFileName(), fileInfo.getWorkspaceId());
        }
        return flag;
    }
}
